﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.Windows.Input;

using NotaManager;
using System.Xml.Serialization;
using System.Windows;
using WpfClient.Views;
using System.Diagnostics;
using System.Windows.Data;
using System.Threading;

namespace WpfClient.Models
{
    public class MainViewModel: ViewModelBase
    {
        private bool _inNovel;
        public bool InNovel { get { return _inNovel; } set { _inNovel = value; RaisePropertyChanged("InNovel"); } }

        public MainWindow Window { get; set; }

        public Script Script { get; set; }

        public IRemember11Manager _rememberManger { get; set; }

        private string _lastError;
        public string LastError { get { return _lastError; } set { _lastError = value; RaisePropertyChanged(); } }

        private LineViewModel _currentLine;

        public LineViewModel CurrentLine { get { return _currentLine; } set { _currentLine = value; RaisePropertyChanged(); } }

        private bool _isShowAllTranslations;

        public bool IsShowAllTranslations
        {
            get { return _isShowAllTranslations; }
            set { _isShowAllTranslations = value; RaisePropertyChanged(); }
        }



        public ObservableCollection<FileViewModel> Files { get; set; }

        private RelayCommand _refreshScript;
        public ICommand RefreshScript 
        { 
            get 
            {
                if (_refreshScript == null)
                {
                    _refreshScript = new RelayCommand(async () =>
                    {
                        var loadingViewModel = new Models.LoadingViewModel("Please wait, script loading...");
                        var _loadingWindow = new LoadingWindow(loadingViewModel);
                        _loadingWindow.ShowInTaskbar = false;
                        _loadingWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                        _loadingWindow.Topmost = true;
                        _loadingWindow.Owner = Application.Current.MainWindow;
                        _loadingWindow.Show();
                        Application.Current.MainWindow.IsEnabled = false;

                        var progressNotifyCallback = (Action<double>)((percent) =>
                        {
                            loadingViewModel.Progress = (int)percent;
                        });

                        try
                        {
                            await updateScript(progressNotifyCallback);
                            
                        }
                        catch (Exception e)
                        {

                            MessageBox.Show(string.Format( 
@"
Случилась критическая ошибка, попробуйте начать загрузку заново. 
А все почему? Потому что NotaBenoid - самый гнилой портал для переводчиков...
Вообще удивляюсь, почему вы решили им пользоваться... 
Информация об ошибке: {0}
                        
                            ", e.Message) , "Гниение");
                        }
                        finally
                        {
                            _loadingWindow.Close();
                            Application.Current.MainWindow.IsEnabled = true;
                        }
                    });
                }

                return _refreshScript;
            } 
        }

        private RelayCommand _updateSetting;

        public ICommand UpdateSettings
        {
            get 
            {
                if (_updateSetting == null)
                {
                    _updateSetting = new RelayCommand(() =>
                    {
                        ClearLastError();
                        var settingsWin = new SettingsWindow(new SettingsViewModel());
                       settingsWin.Owner = Application.Current.MainWindow;

                        settingsWin.ShowDialog();
                    });
                }
                
                return _updateSetting; 
            
            
            }
            
        }

        private RelayCommand _startNovel;

        public ICommand StartNovel
        {
            get 
            {
                if (_startNovel == null)
                {
                    _startNovel = new RelayCommand(() =>
                    {

                        ClearLastError();
                        if (!InNovel)
                        {
                            UnsetInNovel();
                        }
                        else
                        {
                            SetInNovel();
                        }
                    }

                );
                }

                return _startNovel; 
            }
            
        }

        private RelayCommand _showAllTranslations;

        public ICommand ShowAllTranslations
        {
            get
            {
                if (_showAllTranslations == null)
                {
                    _showAllTranslations = new RelayCommand(() =>
                    {
                        IsShowAllTranslations = !IsShowAllTranslations;
                    }

                );
                }
                return _showAllTranslations;
            }
        }

        private void ClearLastError()
        {
            LastError = "";
        }

        private void SetLastError(string error)
        {
            LastError = error;
        }

        private Timer _timer;

        private void SetInNovel()
        {
            if (_timer == null)
            {
                _timer = new Timer(updateFromNovelCallback, null, Timeout.Infinite, Timeout.Infinite);
            }
            InNovel = true;
         
            _timer.Change(0, Timeout.Infinite);
        }

        private void updateFromNovelCallback(object o)
        {
            _timer.Change(Timeout.Infinite, Timeout.Infinite);
            updateFromNovel();

            if (InNovel)
            {
                _timer.Change(500, Timeout.Infinite);
            }
            
        }

        private void UnsetInNovel()
        {
            InNovel = false;
        }

        private void updateFromNovel()
        {
            try
            {
                var procTitle = "R11-English";
                if (SettingsManager.Settings.UseRussian)
                {
                    procTitle = "R11-Russian";
                }
                var currentText = _rememberManger.GetCurrentText(procTitle, russian: SettingsManager.Settings.UseRussian);

                if (currentText == null)
                {
                    throw new InvalidOperationException("Can't find Remember11 window...");
                }

                var matchingLines = GetForLanguage(currentText, SettingsManager.Settings.UseRussian);//new List<LineViewModel>();

                if (matchingLines == null)
                {
                    // Текущая строка уже выбрана
                    return;
                }

                LineViewModel selectedLine = null;

                if (matchingLines.Contains(_currentLine))
                {
                    return;
                }

                if (matchingLines.Count == 0)
                {
                    throw new InvalidOperationException("Can't find Remember11 line in the script");
                }
                else if (matchingLines.Count > 1)
                {
                    Window.Dispatcher.Invoke(() => {

                        var pickWindow = new PickLineWindow(new PickLineViewModel(matchingLines), (model) => { selectedLine = model; });
                        pickWindow.ShowDialog();
                    });
                    
                }
                else
                {
                    selectedLine = matchingLines[0];
                }

                if (selectedLine == null)
                {
                    throw new InvalidOperationException("Line is not specified.");
                }

               

                _currentLine = selectedLine;
                var fileModel = Files.First(file => file.Title == selectedLine.FileName);
                Window.Dispatcher.Invoke(() => { Window.SelectLine(selectedLine, fileModel); });
                ClearLastError();

            }
            catch (Exception e)
            {
                if (InNovel)
                {
                    SetLastError(string.Format("Случилась ошибка при попытке коммуникации с новеллой : {0}", e.Message));
                }
                
                Logger.Exception("Exception for updateFromNovel", e);
            }
           
        }

        private List<LineViewModel> GetForLanguage(string text, bool russian = false)
        {
            var matchingLines = new List<LineViewModel>();
            Func<List<LineViewModel>, List<LineViewModel>> grabber = null;

            if (russian)
            {
                grabber = (file) => {
                    return file.
                        
                        Where(line => line.Line.Rus.Any(rus => string.Equals(rus.Value, text, StringComparison.OrdinalIgnoreCase))).
                        ToList();
                
                };
            }
            else
            {
                grabber = (file) =>
                {
                    return file.
                        Where(line => string.Equals(line.Line.Eng, text, StringComparison.OrdinalIgnoreCase)).ToList();

                };
            }

            if (_currentLine != null)
            {
                if (_currentLine.EqualsTo(text, russian))
                {
                    return null;
                }

                var file = Files.First(f => f.Title == _currentLine.FileName);
                var nextLine = file.Lines.FirstOrDefault(l => l.Number == _currentLine.Number + 1);
                if (nextLine.EqualsTo(text, russian))
                {
                    matchingLines.Add(nextLine);
                    return matchingLines;
                }

                var nextRangeLines = file.Lines.Where(l => l.Number > _currentLine.Number).ToList();
                var linesInNextRange = grabber(nextRangeLines);
                if (linesInNextRange.Any())
                {
                    return linesInNextRange;
                }
            }

            foreach (var file in Files)
            {
                List<LineViewModel> _lines = grabber(file.Lines.ToList());
                matchingLines.AddRange(_lines);
            }

            return matchingLines;
        }



        async private Task updateScript(Action<double> progressNotifyCallback)
        {
            var manager = new DafaultNotaManager();
            var res = await manager.Login(SettingsManager.Settings.Username, SettingsManager.Settings.Password);

            if (res.Status != RequestStatus.Sucessful)
            {
                throw new OperationCanceledException("Can't connect to Nota! Check login or password...");
            }

            Debug.WriteLine("Start loading..");
            var script = await manager.GetTranslation(progressNotifyCallback);

            Debug.WriteLine("End loading..");
            var temp = new XmlSerializer(typeof(Script));
            temp.Serialize(System.IO.File.OpenWrite("base.xml"), script);

            Debug.WriteLine("Saved..");
        }

        public MainViewModel(Script script, IRemember11Manager rememberManager)
        {
            Script = script;
            Files = new ObservableCollection<FileViewModel>(script.Files.Select(file => new FileViewModel(file)));
            //FilesSource = new CollectionViewSource();
            //FilesSource.Source = Files;
            //FilesSource.View.MoveCurrentTo()

            _currentLine = Files.First().Lines.Skip(3).First();

            _rememberManger = rememberManager;
            //InNovel = false;

        }

    }
}
